bitkeeper revision 1.1513.1.1 (42925a6aSZSwfyaVsNzV4psPmpZwZg)
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Mon, 23 May 2005 22:34:18 +0000 (22:34 +0000)
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Mon, 23 May 2005 22:34:18 +0000 (22:34 +0000)
Execute xc_linux_restore in a seperate process so that it can't
crash xend.  Also handle errors passed from xc_linux_restore and
log info messages from xc_linux_restore.
XendDomain.py:
  Popen xc_restore instead of calling xc_linux_restore directly.
xc.c:
  Add pyxc_handle exporting the file descriptor to the control interface.
  Remove xc_linux_restore -- replaced by popen of xc_restore directly
  from python.
xc_linux_restore.c:
  Enable debug output.
xpopen.py:
  Add xpopen functionality:
  Optionally exclude a list of file descriptors from being closed, allowing
  access to those file descriptors from the command.
  Remove unused parts.
xpopen.py, Makefile, xc_restore.c:
  new file
Makefile:
  Add xcutils subdir.
ignore:
  Add tools/xcutils/xc_restore.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
.rootkeys
BitKeeper/etc/ignore
tools/Makefile
tools/libxc/xc_linux_restore.c
tools/python/xen/lowlevel/xc/xc.c
tools/python/xen/util/xpopen.py [new file with mode: 0644]
tools/python/xen/xend/XendDomain.py
tools/xcutils/Makefile [new file with mode: 0644]
tools/xcutils/xc_restore.c [new file with mode: 0644]

index 4ba4305d4b4c38264eff2c907ed338e9cbea856e..8492df053d4624585419e7483a33343eeba3e715 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 41dde8b0yuJX-S79w4xJKxBQ-Mhp1A tools/python/xen/util/memmap.py
 4288c6fcB1kUAqX0gzU85GGxmamS4Q tools/python/xen/util/process.py
 4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py
+4292565fDy2PaatawinIckKB0cKusg tools/python/xen/util/xpopen.py
 4267a9b16u4IEPhjRryesk6A17sobA tools/python/xen/web/SrvBase.py
 4267a9b1FfCUjW7m9anLERcx9lwhJg tools/python/xen/web/SrvDir.py
 4267a9b1uMXIfzB6-81ZLqMCyTgJmw tools/python/xen/web/__init__.py
 41d58ba6R6foSMtSFEcu-yxWFrT8VQ tools/xcs/xcs.h
 41d58ba6qyr2BkTcH2WlNBYLRyl2Yw tools/xcs/xcs_proto.h
 41d58ba6ijEF6fedqRO5vFu7uCirZg tools/xcs/xcsdump.c
+4292540couq-V0TPwyQ6bspNEWNcvw tools/xcutils/Makefile
+42925407VysDb9O06OK_RUzTZxfLoA tools/xcutils/xc_restore.c
 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
 420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c
index 08995a6ab97c3c33e4faffdcae6a4235ab8552a6..8ffdcf5028995df6c36003492533c412a6f32d0c 100644 (file)
@@ -125,6 +125,7 @@ tools/web-shutdown.tap
 tools/x2d2/minixend
 tools/xcs/xcs
 tools/xcs/xcsdump
+tools/xcutils/xc_restore
 tools/xentrace/xentrace
 tools/xfrd/xfrd
 xen/BLOG
index 52ddb9f24be3143f1b3a1a8afc97287ec7908868..9e6c159050fe4b82313b1dbfe1c621d8c59bdb5c 100644 (file)
@@ -10,6 +10,7 @@ SUBDIRS += xentrace
 SUBDIRS += python
 SUBDIRS += xfrd
 SUBDIRS += xcs
+SUBDIRS += xcutils
 SUBDIRS += pygrub
 
 .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
index 7d6aec28591db6b7284bcdbeec3d82faec3ef3a7..c679e9dd5a2e7379d4ddcea11eed667faed79563 100644 (file)
@@ -11,7 +11,7 @@
 
 #define MAX_BATCH_SIZE 1024
 
-#define DEBUG 0
+#define DEBUG 01
 
 #if 1
 #define ERR(_f, _a...) fprintf ( stderr, _f , ## _a )
@@ -20,7 +20,7 @@
 #endif
 
 #if DEBUG
-#define DPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
+#define DPRINTF(_f, _a...) fprintf ( stdout, _f , ## _a )
 #else
 #define DPRINTF(_f, _a...) ((void)0)
 #endif
index 9e6396c75bdccdce82908a903014e4775bc0a1b3..8132ff1047d8dfaa99f75c412209a6b6b3808079 100644 (file)
@@ -63,6 +63,13 @@ static PyObject *pyxc_domain_dumpcore(PyObject *self,
     return NULL;
 }
 
+static PyObject *pyxc_handle(PyObject *self)
+{
+    XcObject *xc = (XcObject *)self;
+
+    return PyInt_FromLong(xc->xc_handle);
+}
+
 static PyObject *pyxc_domain_create(PyObject *self,
                                     PyObject *args,
                                     PyObject *kwds)
@@ -334,36 +341,6 @@ static PyObject *pyxc_linux_save(PyObject *self,
     return val;
 }
 
-static PyObject *pyxc_linux_restore(PyObject *self,
-                                    PyObject *args,
-                                    PyObject *kwds)
-{
-    XcObject *xc = (XcObject *)self;
-    PyObject *val = NULL;
-    int rc =-1;
-    int io_fd, dom;
-    unsigned long nr_pfns;
-
-    static char *kwd_list[] = { "fd", "dom", "pfns", NULL };
-
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iil", kwd_list,
-                                      &io_fd, &dom, &nr_pfns) )
-        goto exit;
-
-    rc = xc_linux_restore(xc->xc_handle, io_fd, dom, nr_pfns);
-    if ( rc != 0 )
-    {
-        PyErr_SetFromErrno(xc_error);
-        goto exit;
-    }
-
-    Py_INCREF(zero);
-    val = zero;
-
-  exit:
-    return val;
-}
-
 static PyObject *pyxc_linux_build(PyObject *self,
                                   PyObject *args,
                                   PyObject *kwds)
@@ -938,6 +915,11 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
 
 
 static PyMethodDef pyxc_methods[] = {
+    { "handle",
+      (PyCFunction)pyxc_handle,
+      0, "\n"
+      "Query the xc control interface file descriptor.\n\n"
+      "Returns: [int] file descriptor\n" },
     { "domain_create", 
       (PyCFunction)pyxc_domain_create, 
       METH_VARARGS | METH_KEYWORDS, "\n"
@@ -1026,14 +1008,6 @@ static PyMethodDef pyxc_methods[] = {
       " progress   [int, 1]: Bool - display a running progress indication?\n\n"
       "Returns: [int] 0 on success; -1 on error.\n" },
 
-    { "linux_restore", 
-      (PyCFunction)pyxc_linux_restore, 
-      METH_VARARGS | METH_KEYWORDS, "\n"
-      "Restore the CPU and memory state of a Linux guest OS.\n"
-      " dom        [int]:    Identifier of domain to be restored.\n"
-      " pfns       [int]:    Number of pages domain uses.\n"
-      "Returns: [int] new domain identifier on success; -1 on error.\n" },
-
     { "linux_build", 
       (PyCFunction)pyxc_linux_build, 
       METH_VARARGS | METH_KEYWORDS, "\n"
diff --git a/tools/python/xen/util/xpopen.py b/tools/python/xen/util/xpopen.py
new file mode 100644 (file)
index 0000000..6b15121
--- /dev/null
@@ -0,0 +1,112 @@
+"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
+
+The normal os.popen(cmd, mode) call spawns a shell command and provides a
+file interface to just the input or output of the process depending on
+whether mode is 'r' or 'w'.  This module provides the functions xpopen2(cmd)
+and xpopen3(cmd) which return two or three pipes to the spawned command.
+Optionally exclude a list of file descriptors from being closed, allowing
+access to those file descriptors from the command.
+"""
+
+import os
+import sys
+
+try:
+    MAXFD = os.sysconf('SC_OPEN_MAX')
+except (AttributeError, ValueError):
+    MAXFD = 256
+
+_active = []
+
+def _cleanup():
+    for inst in _active[:]:
+        inst.poll()
+
+class xPopen3:
+    """Class representing a child process.  Normally instances are created
+    by the factory functions popen2() and popen3()."""
+
+    sts = -1                    # Child not completed yet
+
+    def __init__(self, cmd, capturestderr=False, bufsize=-1, passfd=()):
+        """The parameter 'cmd' is the shell command to execute in a
+        sub-process.  The 'capturestderr' flag, if true, specifies that
+        the object should capture standard error output of the child process.
+        The default is false.  If the 'bufsize' parameter is specified, it
+        specifies the size of the I/O buffers to/from the child process."""
+        _cleanup()
+        self.passfd = passfd
+        p2cread, p2cwrite = os.pipe()
+        c2pread, c2pwrite = os.pipe()
+        if capturestderr:
+            errout, errin = os.pipe()
+        self.pid = os.fork()
+        if self.pid == 0:
+            # Child
+            os.dup2(p2cread, 0)
+            os.dup2(c2pwrite, 1)
+            if capturestderr:
+                os.dup2(errin, 2)
+            self._run_child(cmd)
+        os.close(p2cread)
+        self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+        os.close(c2pwrite)
+        self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+        if capturestderr:
+            os.close(errin)
+            self.childerr = os.fdopen(errout, 'r', bufsize)
+        else:
+            self.childerr = None
+        _active.append(self)
+
+    def _run_child(self, cmd):
+        if isinstance(cmd, basestring):
+            cmd = ['/bin/sh', '-c', cmd]
+        for i in range(3, MAXFD):
+            if i in self.passfd:
+                continue
+            try:
+                os.close(i)
+            except OSError:
+                pass
+        try:
+            os.execvp(cmd[0], cmd)
+        finally:
+            os._exit(1)
+
+    def poll(self):
+        """Return the exit status of the child process if it has finished,
+        or -1 if it hasn't finished yet."""
+        if self.sts < 0:
+            try:
+                pid, sts = os.waitpid(self.pid, os.WNOHANG)
+                if pid == self.pid:
+                    self.sts = sts
+                    _active.remove(self)
+            except os.error:
+                pass
+        return self.sts
+
+    def wait(self):
+        """Wait for and return the exit status of the child process."""
+        if self.sts < 0:
+            pid, sts = os.waitpid(self.pid, 0)
+            if pid == self.pid:
+                self.sts = sts
+                _active.remove(self)
+        return self.sts
+
+
+def xpopen2(cmd, bufsize=-1, mode='t', passfd=[]):
+    """Execute the shell command 'cmd' in a sub-process.  If 'bufsize' is
+    specified, it sets the buffer size for the I/O pipes.  The file objects
+    (child_stdout, child_stdin) are returned."""
+    inst = xPopen3(cmd, False, bufsize, passfd)
+    return inst.fromchild, inst.tochild
+
+def xpopen3(cmd, bufsize=-1, mode='t', passfd=[]):
+    """Execute the shell command 'cmd' in a sub-process.  If 'bufsize' is
+    specified, it sets the buffer size for the I/O pipes.  The file objects
+    (child_stdout, child_stdin, child_stderr) are returned."""
+    inst = xPopen3(cmd, True, bufsize, passfd)
+    return inst.fromchild, inst.tochild, inst.childerr
index d45a3547df188cd15b0f0e0f121c87a3230ba624..2320e8758d6081dbd27dd590eb0552fd76fe99b0 100644 (file)
@@ -25,7 +25,11 @@ from xen.xend.server import channel
 
 
 import errno
+import os
+import select
+from string import join
 from struct import pack, unpack, calcsize
+from xen.util.xpopen import xPopen3
 
 __all__ = [ "XendDomain" ]
 
@@ -325,6 +329,7 @@ class XendDomain:
         sizeof_int = calcsize("i")
         sizeof_unsigned_long = calcsize("L")
         PAGE_SIZE = 4096
+        PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
 
         class XendFile(file):
             def read_exact(self, size, error_msg):
@@ -367,7 +372,29 @@ class XendDomain:
             #             underlying file descriptor
             ignore = fd.tell()
 
-            xc.linux_restore(fd.fileno(), int(dominfo.id), nr_pfns)
+            cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd.fileno()),
+                   dominfo.id, str(nr_pfns)]
+            log.info("[xc_restore] " + join(cmd))
+            child = xPopen3(cmd, True, -1, [fd.fileno(), xc.handle()])
+            child.tochild.close()
+
+            lasterr = ""
+            p = select.poll()
+            p.register(child.fromchild.fileno())
+            p.register(child.childerr.fileno())
+            while True:
+                r = p.poll()
+                for l in child.childerr.readlines():
+                    log.error(l.rstrip())
+                    lasterr = l.rstrip()
+                for l in child.fromchild.readlines():
+                    log.info(l.rstrip())
+                if filter(lambda (fd, event): event & select.POLLHUP, r):
+                    break
+
+            if child.wait() != 0:
+                raise XendError("xc_restore failed: %s" % lasterr)
+            
             return dominfo
 
         except IOError, ex:
diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile
new file mode 100644 (file)
index 0000000..dbdc45d
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# tools/xcutils/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General
+# Public License.  See the file "COPYING" in the main directory of
+# this archive for more details.
+#
+# Copyright (C) 2005 by Christian Limpach
+#
+
+INSTALL                = install
+INSTALL_PROG   = $(INSTALL) -m0755
+INSTALL_DIR    = $(INSTALL) -d -m0755
+
+XEN_ROOT       = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+PROGRAMS_INSTALL_DIR   = /usr/libexec/xen
+
+vpath %.h      $(XEN_LIBXC)
+INCLUDES += -I $(XEN_LIBXC)
+
+CC := gcc
+
+CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
+CFLAGS += $(INCLUDES)
+
+# Make gcc generate dependencies.
+CFLAGS += -Wp,-MD,.$(@F).d
+PROG_DEP = .*.d
+
+PROGRAMS               = xc_restore
+
+xc_restore_OBJS                = xc_restore.o
+xc_restore_LIBS                = xc
+
+.PHONY: all
+all: build
+build: $(PROGRAMS)
+
+define PROGRAM_template
+ $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
+ ALL_OBJS      += $$($(1)_OBJS)
+endef
+
+$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
+
+$(PROGRAMS):
+       $(LINK.o) $^ $(LDLIBS) -o $@
+
+.PHONY: install
+install: build
+       [ -d $(DESTDIR)$(PROGRAMS_INSTALL_DIR) ] || \
+               $(INSTALL_DIR) $(DESTDIR)$(PROGRAMS_INSTALL_DIR)
+       $(INSTALL_PROG) $(PROGRAMS) $(DESTDIR)$(PROGRAMS_INSTALL_DIR)
+
+
+clean:
+       $(RM) $(ALL_OBJS) $(PROGRAMS)
+       $(RM) $(PROG_DEP)
+
+-include $(PROG_DEP)
diff --git a/tools/xcutils/xc_restore.c b/tools/xcutils/xc_restore.c
new file mode 100644 (file)
index 0000000..ebba6d6
--- /dev/null
@@ -0,0 +1,30 @@
+/* 
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2005 by Christian Limpach
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+
+#include <xc.h>
+
+int
+main(int argc, char **argv)
+{
+    unsigned int xc_fd, io_fd, domid, nr_pfns;
+
+    if (argc != 5)
+       errx(1, "usage: %s xcfd iofd domid nr_pfns", argv[0]);
+
+    xc_fd = atoi(argv[1]);
+    io_fd = atoi(argv[2]);
+    domid = atoi(argv[3]);
+    nr_pfns = atoi(argv[4]);
+
+    return xc_linux_restore(xc_fd, io_fd, domid, nr_pfns);
+}